/*
 * Memory.c
 *
 *  Created on: Oct 15, 2018
 *      Author: ax
 */
#include <c6x.h>
#include <Hw/Xmc.h>
#include <Hw/Memory.h>

//see memory's solution for more informations.
#define MAR_HSM         MAR_SHM  //MSMC shadow only, as it's high performance memory, mfence should followed
#define MAR_HP          MAR_PC + MAR_FPX //high performance configuration
#define MAR_SHX         MAR_HP   //SHX - shared executable code segment
#define MAR_SHD         MAR_HP   //SHD - shared data segment
#define MAR_PIX         MAR_HP   //PIX - private executable code segment
#define MAR_PID         MAR_HP   //PID - private data segment
#define MAR_PSD         MAR_SHM  //PSD - private shared data segment.
#define MAR_PQM         MAR_SHM  //PQM - peripheral QMSS
#define MAR_GL2         MAR_SHM  //core's ll2 global

#define MPAX_SHX        MPAX_EN + MPAX_SR + MPAX_SX + MPAX_UR + MPAX_UW
#define MPAX_SHD        MPAX_EN + MPAX_SR + MPAX_SW + MPAX_UR + MPAX_UW
#define MPAX_PIX        MPAX_EN + MPAX_SR + MPAX_SX + MPAX_UR + MPAX_UW
#define MPAX_PID        MPAX_EN + MPAX_SR + MPAX_SW + MPAX_UR + MPAX_UW
#define MPAX_PSD        MPAX_PID
#define MPAX_HSM        MPAX_EXT + MPAX_PID

#define HSM_BASE        0x2C000000u
#define PSD_BASE        0x80000000u
#define SHX_BASE        0xA0000000u
#define SHD_BASE        0xB0000000u
#define PIX_BASE        0xC0000000u
#define PID_BASE        0xD0000000u
#define PQM_BASE        0x34000000u  //QMSS
#define GL2_BASE        0x10000000u


#define PSD_SZ          SEG_512M    //((32+32)*8)
#define SHX_SZ          SEG_64M     //64
#define SHD_SZ          SEG_256M    //256 - 64 == 192M
#define PIX_SZ          SEG_32M     //32M *8
#define PID_SZ          SEG_128M    //128M *8
#define HSM_SZ          SEG_4M
#define PQM_SZ          SEG_2M
#define GBL_SZ          SEG_128M


#define HSM_PA          0x00C000000llu
#define PSD_PA          0x800000000llu
#define SHX_PA          0x82C000000llu
#define SHD_PA          0x820000000llu
#define PIX_PA          0x830000000llu
#define PID_PA          0x840000000llu
#define PQM_PA          0x034000000llu
#define GL2_PA          0x010000000llu


#define ADDR_4K(addr)   (addr >> 12)
#define ADDR_F4K(addr)  (addr << 12)


typedef struct {
    Uint32 base4k : 20;
    Uint32 attr : 4;
    Uint32 coreOffset : 3;//mark this is a private segment with core's offset.
    Uint32 size : 5;

    Uint32 pa4k : 28;
    Uint32 perm : 8;
} Xmc_Configuration;

static const Xmc_Configuration Xmc_Cfg[] = {//becareful here, see Xmc_setup for more info.!
    {ADDR_4K(HSM_BASE), MAR_HSM, 0, HSM_SZ,  ADDR_4K(HSM_PA), MPAX_HSM},
    {ADDR_4K(PSD_BASE), MAR_PSD, 0, PSD_SZ,  ADDR_4K(PSD_PA), MPAX_PSD},
    {ADDR_4K(SHX_BASE), MAR_SHX, 0, SHX_SZ,  ADDR_4K(SHX_PA), MPAX_SHX},
    {ADDR_4K(SHD_BASE), MAR_SHD, 0, SHD_SZ,  ADDR_4K(SHD_PA), MPAX_SHD},
    {ADDR_4K(PIX_BASE), MAR_PIX, 1, PIX_SZ,  ADDR_4K(PIX_PA), MPAX_PIX},
    {ADDR_4K(PID_BASE), MAR_PID, 1, PID_SZ,  ADDR_4K(PID_PA), MPAX_PID},
    {ADDR_4K(GL2_BASE), MAR_GL2, 0, GBL_SZ,  ADDR_4K(GL2_PA), MAPX_NU } //LL2 golbal
//    {ADDR_4K(PQM_BASE), MAR_PQM, 0, SEG_2M,  ADDR_4K(PQM_PA), MAPX_NU },//QMSS
};
const short Xmc_CfgCount = sizeof(Xmc_Cfg) / sizeof(Xmc_Configuration);


void Xmc_setup(CorePac cid, Xmc_Routine routine){
    #ifdef _DBG
    register Uint64* va;

    Uint64 ts = _itoll(TSCH,TSCL);

    for (va = (Uint64*) 0x80000000; va < (Uint64*) 0xFFFFFFC0; va += 4) {
        *(va)   = (Uint64) va;
        *(va+1) = (Uint64) va + 8;
        *(va+2) = (Uint64) va + 16;
        *(va+3) = (Uint64) va + 24;
    }

    ts = _itoll(TSCH, TSCL) - ts; TSCL = ts;
    #endif

    uint16_t mpaxIdx = 15; //larger id has higher priority

    for (Uint8 i = 0; i < Xmc_CfgCount; i++) {
        Uint32 base4k = Xmc_Cfg[i].base4k;
        Uint32 powSize = Xmc_Cfg[i].size;
        Uint32 pa4K = Xmc_Cfg[i].pa4k;

        Uint32 size4k = SEG_4K_SZ(powSize);
        Uint32 end4k = base4k + size4k - 1;
        Uint8 perm = (XMC_ROBUST == routine) ? Xmc_Cfg[i].perm : (Xmc_Cfg[i].perm | MPAX_SW);//BF for all allowed

        Xmc_setMar(base4k, end4k, (Xmc_Attr) Xmc_Cfg[i].attr);

        if ((perm & MPAX_EN) && (XMC_MAP == routine)) {
            if (Xmc_Cfg[i].coreOffset)
                pa4K += (cid * SEG_4K_SZ(powSize));
            Xmc_map(mpaxIdx--, pa4K, base4k, powSize, perm);
        }
        if (mpaxIdx == (uint16_t)-1) return;//no more mpax entry avilable.
    }

    if (XMC_ROBUST == routine) {
        ;//TODO disable global map in mpax[1:0]
    }
}

